#ifndef TIMER_WHEEL_H
#define TIMER_WHEEL_H

#include <cstdint>
#include <cassert>
#include <functional>
#include <memory>

#include <chrono>
#include <list>
#include <utility>
#include <vector>
#include <string>
#include <mutex>
#include <thread>
#include <unordered_set>


namespace TimerWheel {
    //
    inline int64_t get_now_timestamp() {
        using namespace std::chrono;
        auto now_dur = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
        return now_dur.count();
    }

    // 单个计时器
    using TimerTask = std::function<void()>;
    struct Timer {
        uint32_t id;
        int64_t expiry_ms;
        uint32_t interval_ms;
        TimerTask task;
        bool repeated;

        Timer(uint32_t t_id, int64_t t_when_ms, uint32_t t_intvl_ms, TimerTask t_task) : id(t_id),
        expiry_ms(t_when_ms), interval_ms(t_intvl_ms), repeated(t_intvl_ms>0), task(std::move(t_task)) {}
    };
    using TimerPtr = std::shared_ptr<Timer>;


    // 单级时间轮
    class SingleWheel {
    public:
        SingleWheel(uint32_t scales, uint32_t uint_ms, const std::string& name = "");
        ~SingleWheel() = default;
        void set_higher_wheel(SingleWheel *higher_tw);
        void set_lower_wheel(SingleWheel *lower_tw);

        int64_t get_current_time();
        bool insert_timer(const TimerPtr& timer);
        void step();
         std::list<TimerPtr> move_slot();


    private:
        std::string m_name;
        uint32_t m_scales;
        uint32_t m_unit_ms;

        uint32_t m_current_idx;
        std::vector<std::list<TimerPtr>> m_slots;
        SingleWheel *m_higher_wheel;
        SingleWheel *m_lower_wheel;
    };
    using WheelPtr = std::shared_ptr<SingleWheel>;


    //
    class TimerWheels{
    public:
        explicit TimerWheels(uint32_t step_ms = 50);
        ~TimerWheels() {stop();}

        void append_wheel(uint32_t scales, uint32_t unit_ms, const std::string& name = "");
        void start();
        void stop();

        void add_timer(int32_t id, int64_t timeout_ms, const TimerTask &task);
        void add_repeated_timer(int32_t id, int64_t interval_ms, const TimerTask &task);
        void del_timer(uint32_t id);

    private:
        void run();
        WheelPtr get_highest_wheel();
        WheelPtr get_lowest_wheel();

    private:
        bool m_is_stop;
        std::mutex m_mutex;
        std::thread m_thread;
        uint32_t m_minstep_ms;

        std::vector<WheelPtr> m_wheels;
        std::unordered_set<uint32_t> del_timer_ids;
    };

}



#endif //TIMER_WHEEL_H
